package com.ruoyi.pm.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.pubfun.IdWorker;
import com.ruoyi.common.utils.pubfun.JsonMapper;
import com.ruoyi.framework.util.LoginUserUtil;
import com.ruoyi.pm.domain.ExcPortConfig;
import com.ruoyi.pm.mapper.ExcPortConfigMapper;
import com.ruoyi.pm.service.IExcPortConfigService;
import com.ruoyi.pm.service.IExcPortUpdateConditionService;
import com.ruoyi.pm.util.ExcConstant;
import com.ruoyi.pm.util.ExchangeUtil;
import org.apache.commons.lang3.StringEscapeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 接口参数配置Service业务层处理
 *
 * @author ruoyi
 * @date 2022-01-20
 */
@Service
public class ExcPortConfigServiceImpl implements IExcPortConfigService {
    @Autowired
    private ExcPortConfigMapper excPortConfigMapper;

    @Autowired
    private IExcPortUpdateConditionService excPortUpdateConditionService;

    @Autowired
    private RedisCache redisCache;

    final private static String prefix = "exc_port_config:";

    /**
     * 查询接口参数配置
     *
     * @param id 接口参数配置主键
     * @return 接口参数配置
     */
    @Override
    public ExcPortConfig selectExcPortConfigById(Long id) {
        return excPortConfigMapper.selectExcPortConfigById(id);
    }

    /**
     * 查询接口参数配置列表
     *
     * @param portId 接口Id
     * @return 接口参数配置集合
     */
    @Override
    public List<ExcPortConfig> selectExcPortConfigListByPortIdAndType(Long portId,String type){
        //先从缓存里取
        List<ExcPortConfig> excPortConfigList = redisCache.getCacheObject(prefix+ type+ Constants.COLON + portId);
        //判断缓存是否存在
        if (!StringUtils.isArray(excPortConfigList)) {
            ExcPortConfig excPortConfig = new ExcPortConfig();
            excPortConfig.setPortId(portId);
            excPortConfig.setType(type);
            excPortConfigList = excPortConfigMapper.selectExcPortConfigList(excPortConfig);
            //并存入缓存
            if(StringUtils.isArray(excPortConfigList)) {
                redisCache.setCacheObject(prefix+ type + Constants.COLON + portId, excPortConfigList);
            }
        }
        return excPortConfigList;
    }

    /**
     * 查询接口参数配置列表
     *
     * @param excPortConfig 接口参数配置
     * @return 接口参数配置
     */
    @Override
    public List<ExcPortConfig> selectExcPortConfigList(ExcPortConfig excPortConfig) {
        return excPortConfigMapper.selectExcPortConfigList(excPortConfig);
    }

    /**
     * 新增接口参数配置
     *
     * @param excPortConfig 接口参数配置
     * @return 结果
     */
    @Override
    public int insertExcPortConfig(ExcPortConfig excPortConfig) {
        //删缓存
        redisCache.deleteObject(prefix + excPortConfig.getType() + excPortConfig.getPortId());

        if (excPortConfig.getId() != null) {
            return updateExcPortConfig(excPortConfig);
        } else {
            if (!"4".equals(excPortConfig.getType())) {
                ExcPortConfig selectExcPortConfig = new ExcPortConfig();
                selectExcPortConfig.setPortId(excPortConfig.getPortId());
                selectExcPortConfig.setParentId(excPortConfig.getParentId());
                selectExcPortConfig.setField(excPortConfig.getField());
                List<ExcPortConfig> excPortConfigs = excPortConfigMapper.selectExcPortConfigList(excPortConfig);
                if (excPortConfigs != null && excPortConfigs.size() > 0) {
                    throw new BusinessException("该节点已存在此字段，添加失败。");
                }
            }
            //查询最大排序
            Integer orderNum = excPortConfigMapper.selectMaxOrderNum(excPortConfig);
            if (orderNum == null) {
                orderNum = 0;
            }
            orderNum++;
            excPortConfig.setOrderNum(orderNum);
            excPortConfig.setId(IdWorker.getId());
            excPortConfig.setCreateBy(LoginUserUtil.getSysUser().getUserName());
            excPortConfig.setCreateTime(DateUtils.getNowDate());
            excPortConfig.setUpdateBy(LoginUserUtil.getSysUser().getUserName());
            excPortConfig.setUpdateTime(DateUtils.getNowDate());
            return excPortConfigMapper.insertExcPortConfig(excPortConfig);
        }
    }

    /**
     * 新增接口参数配置
     *
     * @param excPortConfigList 接口参数配置集合
     * @return 结果
     */
    @Override
    public int insertExcPortConfigList(List<ExcPortConfig> excPortConfigList, Long portId) {
        ExcPortConfig excPortConfig0 = excPortConfigList.get(0);
        ExcPortConfig selectExcPortConfig = new ExcPortConfig();
        selectExcPortConfig.setPortId(excPortConfig0.getPortId());
        selectExcPortConfig.setType("4");
        List<ExcPortConfig> excPortConfigs = excPortConfigMapper.selectExcPortConfigList(selectExcPortConfig);
        //删缓存
        redisCache.deleteObject(prefix + excPortConfig0.getType() + excPortConfig0.getPortId());
        //查询最大排序
        Integer orderNum = excPortConfigMapper.selectMaxOrderNum(selectExcPortConfig);
        if (orderNum == null) {
            orderNum = 0;
        }
        List<Long> ids = new ArrayList<>();
        for (ExcPortConfig excPortConfig : excPortConfigList) {
            excPortConfig.setType("4");
            excPortConfig.setPortId(portId);

            if (excPortConfig.getId() != null) {
                if (StringUtils.isEmpty(excPortConfig.getMappingFormula())) {
                    ids.add(excPortConfig.getId());
                } else {
                    if (excPortConfigs.stream().anyMatch(config -> config.getParentId().equals(excPortConfig.getParentId()) && config.getField().equals(excPortConfig.getField()) && !config.getId().equals(excPortConfig.getId()))) {
                        throw new BusinessException("该节点已存在此字段，添加失败。");
                    }

                    if (excPortConfigs.stream().anyMatch(config -> config.getParentId().equals(excPortConfig.getParentId()) && ((StringUtils.isEmpty(config.getMappingFormula()) && StringUtils.isEmpty(excPortConfig.getMappingFormula())) || (StringUtils.isNotEmpty(config.getMappingFormula()) && config.getMappingFormula().equals(excPortConfig.getMappingFormula()))) && config.getId().equals(excPortConfig.getId()))) {
                        continue;
                    }

                    excPortConfig.setUpdateBy(LoginUserUtil.getSysUser().getUserName());
                    excPortConfig.setUpdateTime(DateUtils.getNowDate());
                    excPortConfigMapper.updateExcPortConfig(excPortConfig);
                }
            } else {
                if (StringUtils.isNotEmpty(excPortConfig.getMappingFormula())) {
                    if (!"4".equals(excPortConfig.getType()) && excPortConfigs != null && excPortConfigs.size() > 0) {
                        if (excPortConfigs.stream().anyMatch(config -> config.getParentId().equals(excPortConfig.getParentId()) && config.getField().equals(excPortConfig.getField()))) {
                            throw new BusinessException("该节点已存在此字段，添加失败。");
                        }
                    }
                    orderNum++;
                    excPortConfig.setOrderNum(orderNum);
                    excPortConfig.setId(IdWorker.getId());
                    excPortConfig.setCreateBy(LoginUserUtil.getSysUser().getUserName());
                    excPortConfig.setCreateTime(DateUtils.getNowDate());
                    excPortConfig.setUpdateBy(LoginUserUtil.getSysUser().getUserName());
                    excPortConfig.setUpdateTime(DateUtils.getNowDate());
                    excPortConfigMapper.insertExcPortConfig(excPortConfig);
                }
            }
        }
        if (ids.size() > 0) {
            excPortConfigMapper.deleteExcPortConfigByIds(ids.toArray(new Long[ids.size()]));
        }
        return excPortConfigList.size();
    }

    /**
     * 修改接口参数配置
     *
     * @param excPortConfig 接口参数配置
     * @return 结果
     */
    @Override
    public int updateExcPortConfig(ExcPortConfig excPortConfig) {
        //删缓存
        redisCache.deleteObject(prefix + excPortConfig.getType() + excPortConfig.getPortId());

        ExcPortConfig selectExcPortConfig = new ExcPortConfig();
        selectExcPortConfig.setPortId(excPortConfig.getPortId());
        selectExcPortConfig.setParentId(excPortConfig.getParentId());
        selectExcPortConfig.setField(excPortConfig.getField());
        List<ExcPortConfig> excPortConfigs = excPortConfigMapper.selectExcPortConfigList(excPortConfig);
        if (excPortConfigs != null && excPortConfigs.size() > 0 && !excPortConfig.getId().equals(excPortConfigs.get(0).getId())) {
            throw new BusinessException("该节点已存在此字段，更新失败。");
        }
        if (StringUtils.isEmpty(excPortConfig.getMappingFormula())) {
            excPortConfig.setMappingFormula("null");
        }
        excPortConfig.setUpdateBy(LoginUserUtil.getSysUser().getUserName());
        excPortConfig.setUpdateTime(DateUtils.getNowDate());
        return excPortConfigMapper.updateExcPortConfig(excPortConfig);

    }

    /**
     * 修改排序
     *
     * @param excPortConfigs 需要排序的两个集合
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateOrderNum(List<ExcPortConfig> excPortConfigs) {
        ExcPortConfig excPortConfig0 = excPortConfigs.get(0);
        ExcPortConfig excPortConfig1 = excPortConfigs.get(1);
        //删缓存
        redisCache.deleteObject(prefix + excPortConfig0.getType() + excPortConfig0.getPortId());
        Integer orderNum = excPortConfig0.getOrderNum();
        excPortConfig0.setOrderNum(excPortConfig1.getOrderNum());
        excPortConfig0.setUpdateBy(LoginUserUtil.getSysUser().getUserName());
        excPortConfig0.setUpdateTime(DateUtils.getNowDate());
        excPortConfig1.setOrderNum(orderNum);
        excPortConfig1.setUpdateBy(LoginUserUtil.getSysUser().getUserName());
        excPortConfig1.setUpdateTime(DateUtils.getNowDate());
        excPortConfigMapper.updateExcPortConfig(excPortConfig0);
        excPortConfigMapper.updateExcPortConfig(excPortConfig1);
        return 2;
    }

    /**
     * 批量删除接口参数配置
     *
     * @param ids 需要删除的接口参数配置主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteExcPortConfigByIds(Long[] ids) {


        ExcPortConfig excPortConfig = excPortConfigMapper.selectExcPortConfigById(ids[0]);
        //删缓存
        redisCache.deleteObject(prefix + excPortConfig.getType() + excPortConfig.getPortId());
        return excPortConfigMapper.deleteExcPortConfigByIds(ids);
    }

    /**
     * 批量删除接口参数配置
     *
     * @param portId 接口id
     * @param type   参数类型
     * @return 结果
     */
    @Override
    public int delByPortIdAndType(Long portId, String type) {
        //删缓存
        redisCache.deleteObject(prefix + type + portId);
        return excPortConfigMapper.delByPortIdAndType(portId, type);
    }

    /**
     * 删除接口参数配置信息
     *
     * @param id 接口参数配置主键
     * @return 结果
     */
    @Override
    public int deleteExcPortConfigById(Long id) {
        ExcPortConfig excPortConfig = excPortConfigMapper.selectExcPortConfigById(id);
        //删缓存
        redisCache.deleteObject(prefix + excPortConfig.getType() + excPortConfig.getPortId());
        //删除规则配置
        excPortUpdateConditionService.deleteByPortConfigId(id,excPortConfig.getPortId());
        return excPortConfigMapper.deleteExcPortConfigById(id);
    }

    /**
     * 删除接口参数配置信息
     *
     * @param portId 接口Id
     * @return 结果
     */
    @Override
    public int deleteExcPortConfigByPortId(Long portId) {
        redisCache.deleteObject(prefix + "1" + portId);
        redisCache.deleteObject(prefix + "2" + portId);
        return excPortConfigMapper.deleteExcPortConfigByPortId(portId);
    }

    /**
     * 报文导入
     *
     * @param excPortConfig 接口参数配置
     * @param saveType      1全量添加，2增量添加
     */
    @Override
    @Transactional(readOnly = false)
    public void saveJsonData(ExcPortConfig excPortConfig, String saveType) {
        // 这里完全是添加一个全新的配置
        // 首先判断数据库是否存在
        /*List<ExcPortConfig> excPortConfigList = excPortConfigMapper.selectExcPortConfigList(excPortConfig);
        if (excPortConfigList != null && excPortConfigList.size() > 0) {
            throw new BusinessException("已经存在该接口下该类型的参数配置。");
        }*/
        try {
            generatePConfig(StringEscapeUtils.unescapeHtml4(excPortConfig.getJsonData()), excPortConfig.getPortId(),
                    excPortConfig.getType(), saveType);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("保存数据失败");
        }
    }


    /**
     * 生成接口配置信息
     *
     * @param type
     * @throws IOException
     * @throws JsonProcessingException
     */

    @Transactional(readOnly = false)
    public void generatePConfig(String body, Long portId, String type, String saveType) throws JsonProcessingException, IOException {

        String jsonBody = ExchangeUtil.xmlToJson(body);

        // 对于保险公司的这里首先需要判断是啥格式的把
        // 也不知道配置人是不是sb，如果是xml 非要搞个json，或者反的也无所谓
        if (jsonBody == null) {
            jsonBody = body;
        }

        JsonNode root = JsonMapper.getInstance().readTree(jsonBody);

        // 判断json是否满足
        if (root == null) {
            throw new BusinessException("保存的json格式不正确");
        }
        if ("1".equals(saveType)) {
            excPortConfigMapper.delByPortIdAndType(portId, type);
        }
        decodePConfigJsonNode(null, root, portId, type, saveType);
    }

    private void decodePConfigJsonNode(ExcPortConfig portConfig, JsonNode root, Long portId, String type, String saveType) {

        Iterator<String> keys = root.fieldNames();

        JsonNode o;
        String key;
        int orderNum = 1;
        while (keys.hasNext()) {
            key = keys.next();
            o = root.path(key);

            if (o.isArray()) {
                for (JsonNode node : o) {
                    decodePConfigJsonNode(createPConfig(portConfig, portId, type, key, null, ExcConstant.ColumnEnum.List.getValue(), orderNum, saveType),
                            node, portId, type, saveType);
                    // 暂时我们就不循环多次了，如果说要取第0个啥的，蛋疼，那种以后子啊考虑
                    break;
                }
            } else if (o.isObject()) {
                decodePConfigJsonNode(createPConfig(portConfig, portId, type, key, null, ExcConstant.ColumnEnum.Map.getValue(), orderNum, saveType), o,
                        portId, type, saveType);
            } else {
                createPConfig(portConfig, portId, type, key, o.textValue(), ExcConstant.ColumnEnum.Value.getValue(), orderNum, saveType);
                orderNum++;
            }
        }
    }

    private ExcPortConfig createPConfig(ExcPortConfig parent, Long portId, String type, String field, String fieldName, String fieldType, int orderNum, String saveType) {
        ExcPortConfig portConfig = new ExcPortConfig();

        portConfig.setPortId(portId);
        portConfig.setType(type);
        portConfig.setField(field);
        if (parent == null) {
            portConfig.setParentId(100L);
            portConfig.setAncestors("100");
        } else {
            portConfig.setParentId(parent.getId());
            portConfig.setAncestors(parent.getAncestors() + "," + parent.getId());
        }
        if ("2".equals(saveType)) {
            List<ExcPortConfig> excPortConfigList = excPortConfigMapper.selectExcPortConfigList(portConfig);
            if (excPortConfigList != null && excPortConfigList.size() > 0) {
                return excPortConfigList.get(0);
            }
        }

        portConfig.setId(IdWorker.getId());
        portConfig.setOrderNum(orderNum);
        portConfig.setFieldType(fieldType);

        if (fieldName == null || "".equals(fieldName.trim())) {
            portConfig.setFieldName(field);
        } else {
            portConfig.setFieldName(fieldName);
        }

        excPortConfigMapper.insertExcPortConfig(portConfig);

        return portConfig;
    }
}
